/****************************************Copyright (c)**********************************************
**                               襄阳润天航空科技有限责任公司
**                                     
**                                 http://www.???.com
**
**--------------File Info---------------------------------------------------------------------------
** 文 件 名 : NowCoo(coordinate)Dis(dispose)Task.c		现在坐标处理任务程序
** 作    者 : 李海洋
** 版    本 ：v1.0
** 完成时间 : 2015年1月30日
** 描    述 ：在1个任务下，分别受方位角、高低角和距离串口接收完成中断服务程序产生的消息结构队列来控
							制。超时定为同步后绝对3ms。支持FreeRTOS8.1.2
							通过SPI与FRAM通讯，DMA模式
**--------------------------------------------------------------------------------------------------
** 修 改 人 ：
** 版    本 ：
** 修改时间 : 年月日
** 修改内容 : 
***************************************************************************************************/
#include "SPI_Driver.h"

#if	USE_SPI_NUM != 0
/*
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
*											 私有宏(常量)定义区		private CONSTANTS
#define ...
enum {.,.,.}XXX;
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
*/
/*
PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
*											  公有变量定义区		public VARIABLES
PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
*/
/*
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
*											  私有变量定义区		private VARIABLES
static ...;
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
*/
sSPI_DRIVER		spi_drive[USE_SPI_NUM]; //
/*
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
*											  私有函数原型定义区		private FUNCTION PROTOTYPES
*	用于解决内部调用函数时以先定义后使用原则相矛盾的函数预定义
static ...;
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
*/
/*  
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
*												私有函数源程序		private SOURCE PROGRAM
static ...(...)
{
}
VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
*/
/*  
##########################################################################################
*												公有函数源程序		public SOURCE PROGRAM
##########################################################################################
*/
/*
********************************************************************************
** 函数名称 :	SPI发送完成中断回调函数
** 描    述 :	所有SPI发送完成中断回调函数都到这里，因此要判断是哪个串口。
这个是由DMA接收完成中断中回调的，不是SPI中断！
** 输入参数 :	SPI_HandleTypeDef *hspi		指向SPI句柄
** 返    回 :	无
********************************************************************************/
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
	for (int i = 0; i < USE_SPI_NUM; i++) {
		if (hspi == spi_drive[i].phspi) {
			//通知已发送完成
#ifdef	NO_USE_FREE_RTOS
			spi_drive[i].DoneFlag = 1;
#else
			osSemaphoreRelease(spi_drive[i].DoneSemId); //通知已发送完成
#endif
			break;
		}
	}
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
	for (int i = 0; i < USE_SPI_NUM; i++) {
		if (hspi == spi_drive[i].phspi) {
			//通知已接收完成
#ifdef	NO_USE_FREE_RTOS
			spi_drive[i].DoneFlag = 1;
#else
			osSemaphoreRelease(spi_drive[i].DoneSemId); //通知已发送完成
#endif
			break;
		}
	}
}
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
	for (int i = 0; i < USE_SPI_NUM; i++) {
		if (hspi == spi_drive[i].phspi) {
			//通知已接收完成
#ifdef	NO_USE_FREE_RTOS
			spi_drive[i].DoneFlag = 1;
#else
			osSemaphoreRelease(spi_drive[i].DoneSemId); //通知已发送完成
#endif
			break;
		}
	}
}
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
	for (int i = 0; i < USE_SPI_NUM; i++) {
		if (hspi == spi_drive[i].phspi) {
			//通知已接收完成
#ifdef	NO_USE_FREE_RTOS
			spi_drive[i].DoneFlag = 1;
#else
			osSemaphoreRelease(spi_drive[i].DoneSemId); //通知已发送完成
#endif
			break;
		}
	}
}
/*
********************************************************************************
** 函数名称 :	SPI_Init
** 描    述 :	注册SPI驱动变量并初始化
** 输入参数 :	见函数定义
** 返    回 :	0:成功；1--重复初始化已经注册过了；-1--spi_drive变量已经用完，需调整USE_SPI_NUM数据。
********************************************************************************/
#ifndef	NO_USE_FREE_RTOS
int SPI_Init(sSPI_DRIVER **pDriver/*[O]指向指向SPI驱动结构的指针*/,				
	SPI_HandleTypeDef *hspi/*[I]指向SPI句柄*/,				
	osSemaphoreId DoneSemId/*[I]SPI通讯完成信号量句柄或ID号*/)
#else
	int SPI_Init(sSPI_DRIVER				**pDriver,				/*[O]指向指向SPI驱动结构的指针*/
	SPI_HandleTypeDef	*hspi)						/*[I]指向SPI句柄*/
#endif
{
	for (int i = 0; i < USE_SPI_NUM; i++) {
		if (spi_drive[i].phspi == NULL) {
			spi_drive[i].phspi = hspi;
#ifndef	NO_USE_FREE_RTOS
			spi_drive[i].DoneSemId = DoneSemId;
			osSemaphoreWait(DoneSemId, 100); //清除创建时默认生成的1个信号量
#else
			spi_drive[i].DoneFlag = 0;
#endif
			*pDriver = &spi_drive[i];
			//			__HAL_SPI_ENABLE(hspi);	//可以不要，启动传输时会自动打开
			return 0;
		}
		if (spi_drive[i].phspi == hspi) {
			*pDriver = &spi_drive[i];
			return 1;
		}
	}
	return -1;
}
/*
********************************************************************************
** 函数名称 :	SPI_Only_Tx
** 描    述 :	SPI在只发送模式下发送数据
** 输入参数 :	见函数定义
** 返    回 :	0=成功，-1=访问HAL出错，其它=hspi1.ErrorCode
********************************************************************************/
int SPI_Only_Tx(sSPI_DRIVER				*pDriver,	/*[IN]指向SPI驱动结构*/
	unsigned char			*pDat,		/*[IN]指向要发送的数据存放处*/
	unsigned short		size)			/*[IN]发送数据字节个数*/
{
	//====局部变量定义

  //====初始化
	
	//====功能程序
	//1启动传输
	if (pDriver->phspi->hdmatx == NULL) {
		//由CubeMX配置决定
		if (HAL_SPI_Transmit_IT(pDriver->phspi, pDat, size) != HAL_OK)
			return -1;
	}
	else {
		if (HAL_SPI_Transmit_DMA(pDriver->phspi, pDat, size) != HAL_OK) {
			return -1;
		}
	}
	//2等待传输结束
#ifdef	NO_USE_FREE_RTOS
	while (pDriver->DoneFlag == 0)
		HAL_PWR_EnterSLEEPMode(0, PWR_SLEEPENTRY_WFI);
	pDriver->DoneFlag = 0;
#else
	osSemaphoreWait(pDriver->DoneSemId, osWaitForever);
#endif
	return pDriver->phspi->ErrorCode;
}
/*
********************************************************************************
*描    述 : SPI在只接收模式下接收数据
*返    回 : 0=成功，-1=访问HAL出错，其它=hspi1.ErrorCode
********************************************************************************/
int SPI_Only_Rx(sSPI_DRIVER *pDriver/*[IN]指向SPI驱动结构*/,
	unsigned char *pDat/*[OUT]指向接收的数据存放处*/,
	unsigned short size/*[IN]接收数据字节个数*/)
{
	//====局部变量定义

  //====初始化
	
	//====功能程序
	//1启动传输
	if (pDriver->phspi->hdmarx == NULL) {
		//由CubeMX配置决定
		if (HAL_SPI_Receive_IT(pDriver->phspi, pDat, size) != HAL_OK)
			return -1;
	}
	else {
		if (HAL_SPI_Receive_DMA(pDriver->phspi, pDat, size) != HAL_OK) {
			return -1;
		}
	}
	//2等待传输结束
#ifdef	NO_USE_FREE_RTOS
	while (pDriver->DoneFlag == 0)
		HAL_PWR_EnterSLEEPMode(0, PWR_SLEEPENTRY_WFI);
	pDriver->DoneFlag = 0;
#else
	osSemaphoreWait(pDriver->DoneSemId, osWaitForever);
#endif
	return pDriver->phspi->ErrorCode;
}
/*
********************************************************************************
** 函数名称 :	SPI_Tx_Rx
** 描    述 :	同时发送和接收(读写)SPI外设数据
** 输入参数 :	见函数定义
** 返    回 :	0=成功，-1=访问HAL出错，其它=hspi1.ErrorCode
********************************************************************************/
int SPI_Tx_Rx(sSPI_DRIVER				*pDriver,	/*[IN]指向SPI驱动结构*/
	unsigned char			*pRxBuf,	/*[OUT]指向接收数据存放位置*/
	unsigned char			*pTxBuf,	/*[IN]指向发送数据存放位置*/
	unsigned short		size)			/*[IN]传输字节数*/
{
	//====功能程序
	//1启动发送和接收
	if (pDriver->phspi->hdmarx == NULL) {
		//由CubeMX配置决定
		if (HAL_SPI_TransmitReceive_IT(pDriver->phspi, pTxBuf, pRxBuf, size) != HAL_OK)
			return -1;
	}
	else {
		if (HAL_SPI_TransmitReceive_DMA(pDriver->phspi, pTxBuf, pRxBuf, size) != HAL_OK)
			return -1;
	}
	//2等待传输结束: DMA接收完成中断信号量
//	do {
//		if ((HardWare.HW.bIWDEn == 1) && (HAL_IWDG_Refresh(&hiwdg) != HAL_OK))
//			Error_Handler(ERR_WDG);
//	}while(osSemaphoreWait(FRAM_RxCpltSemHandle, 10) != osOK);	//osWaitForever);		//在stm32f4xx_it.c的回调函数中触发
#ifdef	NO_USE_FREE_RTOS
	while (pDriver->DoneFlag == 0)
		HAL_PWR_EnterSLEEPMode(0, PWR_SLEEPENTRY_WFI);
	pDriver->DoneFlag = 0;
#else
	osSemaphoreWait(pDriver->DoneSemId, osWaitForever);
#endif
	return pDriver->phspi->ErrorCode;
}

#endif
/*  
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
*												结束	the End !
EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
*/
